﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Web7.Domain;
using Web7.Extensions;
using System.Text.RegularExpressions;
using System.Collections;
using System.Reflection;

namespace Web7.Core.Security
{
    /// <summary>
    /// 表达式之间 
    /// 要嘛是 并且  And && 
    /// 要嘛是 或者  Or ||
    /// </summary>
    ///<remarks>
    ///表达式之间的逻辑
    /// </remarks>
    public enum ExpressionLogic
    {
        And,
        Or
    }

    /// <summary>
    /// 一个表达式的组成
    /// </summary>
    public class ExpressionModel
    {
        public string Key { get; set; }

        public string Operator { get; set; }

        public string Value { get; set; }
    }

    public class ExpressionModelNode
    {
        private ExpressionModel _data;

        private ExpressionLogic _logic;

        public ExpressionModelNode(ExpressionModel Node)
        {
            _data = Node;
        }

        public ExpressionModel Data
        {
            get
            {
                return _data;
            }
            set
            {
                _data = value;
            }
        }

        public ExpressionLogic Logic
        {
            get
            {
                return _logic;
            }
            set
            {
                _logic = value;
            }
        }
    }

    public class ExpressionContext
    {
        public Entity Content { get; set; }

        public bool LogicValue { get; set; }

        public bool ExpressionLogincValue { get; set; }
    }

    public enum KeyValueLogic
    {
        MoreThan,         ///大于     >
        MoreThanEquals,   ///大于等于 >=
        LessThan,         ///小于     <
        LessThanEquals,   ///小于等于 <=
        Equals,           ///等于     ==
        NotEquals         ///不等于   !=   
    }

    public class ExpressionResolverService : IExpressionResolve
    {
        private LinkedList<ExpressionModelNode> linkedList;

        private Dictionary<string, KeyValueLogic> keyValueLogic = new Dictionary<string, KeyValueLogic>();

        public ExpressionResolverService(string expressionString)
        {
            keyValueLogic.Add(">", KeyValueLogic.MoreThan);
            keyValueLogic.Add(">=", KeyValueLogic.MoreThanEquals);
            keyValueLogic.Add("<", KeyValueLogic.LessThan);
            keyValueLogic.Add("<=", KeyValueLogic.LessThanEquals);
            keyValueLogic.Add("==", KeyValueLogic.Equals);
            keyValueLogic.Add("!=", KeyValueLogic.NotEquals);

            if (!string.IsNullOrWhiteSpace(expressionString))
            {
                linkedList = CreateLinkedList(expressionString);
            }
        }

        public ExpressionContext ExpressionContent { get; set; }

        public ExpressionLogic Logic { get; set; }

        public bool ExecuteExpression()
        {
            bool result = false;

            bool isFirst = true;

            var node = linkedList.Head;

            while (node != null)
            {
                var item = node.Data;

                #region Get Entity information
                var property = ExpressionContent.Content.GetType().GetProperty(item.Data.Key);
                var value = property.GetValue(ExpressionContent.Content, null);
                var type = property.PropertyType;
                #endregion

                ExpressionContent.LogicValue = GetLogicValue(type, value, item.Data.Value, GetLogic(item.Data.Operator));

                if (isFirst)
                {
                    ExpressionContent.ExpressionLogincValue = ExpressionContent.LogicValue;
                    isFirst = false;
                }
                else
                {
                    result = ExpressionContent.ExpressionLogincValue = GetResult(ExpressionContent.ExpressionLogincValue, ExpressionContent.LogicValue, Logic);
                    if (Logic == ExpressionLogic.Or && result) return result;
                }
                Logic = item.Logic;
                node = node.Next;
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="expressionString"></param>
        /// <remarks>
        /// example : "test1 == \"\" and test2>200 or test3==\"shit\""
        /// </remarks>
        /// <returns></returns>
        private LinkedList<ExpressionModelNode> CreateLinkedList(string expressionString)
        {
            LinkedList<ExpressionModelNode> _linkedList = new LinkedList<ExpressionModelNode>();

            #region Resolver
            Queue queue = new Queue();

            StringBuilder tmpExpression = new StringBuilder();
            StringBuilder tmpOperator = new StringBuilder();

            for (int i = 0; i < expressionString.Length; i++)
            {
                if (IsBlankChar(expressionString[i]))
                {
                    if (tmpExpression.Length > 0)
                    {
                        queue.Enqueue(tmpExpression.ToString());
                        tmpExpression.Clear();
                    }
                    if (tmpOperator.Length > 0)
                    {
                        queue.Enqueue(tmpOperator.ToString());
                        tmpOperator.Clear();
                    }
                    continue;
                }

                if (ValidatedChar(expressionString[i]))
                {
                    if (tmpOperator.Length > 0)
                    {
                        queue.Enqueue(tmpOperator.ToString());
                        tmpOperator.Clear();
                    }

                    tmpExpression.Append(expressionString[i]);
                }
                else
                {
                    if (tmpExpression.Length > 0)
                    {
                        queue.Enqueue(tmpExpression.ToString());
                        tmpExpression.Clear();
                    }

                    tmpOperator.Append(expressionString[i]);
                }
            }

            if (tmpExpression.Length > 0)
            {
                queue.Enqueue(tmpExpression.ToString());
                tmpExpression.Clear();
            }
            if (tmpOperator.Length > 0)
            {
                queue.Enqueue(tmpOperator.ToString());
                tmpOperator.Clear();
            }

            #endregion

            while (queue.Count > 0)
            {
                ExpressionModel expressionModel = new ExpressionModel();
                expressionModel.Key = queue.Dequeue().ToString();
                expressionModel.Operator = queue.Dequeue().ToString();
                expressionModel.Value = queue.Dequeue().ToString();
                ExpressionModelNode node = new ExpressionModelNode(expressionModel);

                if (queue.Count > 0)
                {
                    node.Logic = (ExpressionLogic)Enum.Parse(typeof(ExpressionLogic), queue.Dequeue().ToString(), true);
                }
                _linkedList.Add(node);
            }

            return _linkedList;
        }

        private bool GetResult(bool target, bool source, ExpressionLogic logic)
        {
            switch (logic)
            {
                case ExpressionLogic.And:
                    return target & source;
                    break;
                case ExpressionLogic.Or:
                    return target | source;
                    break;
            }
            return false;
        }

        private bool GetLogicValue(Type type, object sourceValue, object targetValue, KeyValueLogic keyValueLogic)
        {
            switch (keyValueLogic)
            {
                case KeyValueLogic.MoreThan:
                    if (type.ToString() == "System.Int32")
                    {
                        return int.Parse(sourceValue.ToString()) > int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Decimal")
                    {
                        return decimal.Parse(sourceValue.ToString()) > int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Double")
                    {
                        return double.Parse(sourceValue.ToString()) > int.Parse(targetValue.ToString());
                    }
                    break;
                case KeyValueLogic.MoreThanEquals:
                    if (type.ToString() == "System.Int32")
                    {
                        return int.Parse(sourceValue.ToString()) >= int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Decimal")
                    {
                        return decimal.Parse(sourceValue.ToString()) >= int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Double")
                    {
                        return double.Parse(sourceValue.ToString()) >= int.Parse(targetValue.ToString());
                    }
                    break;
                case KeyValueLogic.LessThan:
                    if (type.ToString() == "System.Int32")
                    {
                        return int.Parse(sourceValue.ToString()) < int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Decimal")
                    {
                        return decimal.Parse(sourceValue.ToString()) < int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Double")
                    {
                        return double.Parse(sourceValue.ToString()) < int.Parse(targetValue.ToString());
                    }
                    break;
                case KeyValueLogic.LessThanEquals:
                    if (type.ToString() == "System.Int32")
                    {
                        return int.Parse(sourceValue.ToString()) <= int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Decimal")
                    {
                        return decimal.Parse(sourceValue.ToString()) <= int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Double")
                    {
                        return double.Parse(sourceValue.ToString()) <= int.Parse(targetValue.ToString());
                    }
                    break;
                case KeyValueLogic.Equals:
                    if (type.ToString() == "System.Int32")
                    {
                        return int.Parse(sourceValue.ToString()) == int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Decimal")
                    {
                        return decimal.Parse(sourceValue.ToString()) == int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Double")
                    {
                        return double.Parse(sourceValue.ToString()) == int.Parse(targetValue.ToString());
                    }
                    else
                    {
                        return sourceValue.Equals(targetValue);
                    }
                    break;
                case KeyValueLogic.NotEquals:
                    if (type.ToString() == "System.Int32")
                    {
                        return int.Parse(sourceValue.ToString()) != int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Decimal")
                    {
                        return decimal.Parse(sourceValue.ToString()) != int.Parse(targetValue.ToString());
                    }
                    else if (type.ToString() == "System.Double")
                    {
                        return double.Parse(sourceValue.ToString()) != int.Parse(targetValue.ToString());
                    }
                    else
                    {
                        return !sourceValue.Equals(targetValue);
                    }
                    break;
            }

            return false;
        }

        private KeyValueLogic GetLogic(string key)
        {
            if (keyValueLogic.ContainsKey(key))
            {
                return keyValueLogic[key];
            }
            return KeyValueLogic.Equals;
        }

        private bool IsBlankChar(char c)
        {
            if (c == 32)
            {
                return true;
            }

            return false;
        }

        private bool ValidatedChar(char c)
        {
            if ((c > 47 && c < 58) ||   ///数字
                (c > 64 && c < 91) ||   ///大写字母
                (c > 96 && c < 123) ||  ///小写字母
                c == 95 ||              ///下划线
                c == 34)                ///引号
            {
                return true;
            }

            return false;
        }
    }

    public class Node<T>
    {
        private T tData;
        private Node<T> nNext;
        public T Data
        {
            get { return tData; }
            set { tData = value; }
        }
        public Node<T> Next
        {
            get { return nNext; }
            set { nNext = value; }
        }
        public Node()
        {
            tData = default(T);
            nNext = null;
        }
        public Node(T t)
        {
            tData = t;
            nNext = null;
        }
        public Node(T t, Node<T> node)
        {
            tData = t;
            nNext = node;
        }
    }

    public enum AddPosition { Head, Tail };

    public interface ILinkedList<T>
    {
        int GetLength();
        void Insert(T item, int i);
        void Add(T item);
        bool IsEmpty();
        T GetElement(int i);
        void Delete(int i);
        void Clear();
        int LocateElement(T item);
        void Reverse();
    }

    public class LinkedList<T> : ILinkedList<T>
    {
        private Node<T> tHead;

        public Node<T> Head
        {
            get { return this.tHead; }
            set { this.tHead = value; }
        }

        public LinkedList()
        {
            this.tHead = null;
        }

        public LinkedList(Node<T> node)
        {
            this.tHead = node;
        }

        public void Add(T item, AddPosition p)
        {
            if (p == AddPosition.Tail)
            {
                this.Add(item);
            }
            else
            {
                Node<T> node = this.Head;
                Node<T> nodeTmp = new Node<T>(item);
                if (node == null)
                {
                    this.Head = nodeTmp;
                }
                else
                {
                    nodeTmp.Next = node;
                    this.tHead = nodeTmp;
                }
            }
        }

        #region IListDS<T> 成员

        public int GetLength()
        {
            Node<T> node = new Node<T>();
            int count = 0;
            node = this.tHead;
            while (node != null)
            {
                count++;
                node = node.Next;
            }
            return count;
        }

        public void Insert(T item, int i)
        {
            Node<T> insertNode = new Node<T>(item, null);
            if (this.tHead == null && i == 1)
            {
                this.tHead = insertNode;
                return;
            }
            if (i < 1 || i > this.GetLength() || (this.tHead == null && i != 1))
            {
                Console.WriteLine("There are no elements in this linked list!");
                return;
            }
            int j = 1;
            Node<T> node = this.tHead;
            Node<T> nodeTmp;
            while (node != null && j < i)
            {
                node = node.Next;
                j++;
            }
            nodeTmp = node.Next;
            node.Next = insertNode;
            insertNode.Next = nodeTmp;
        }

        public void Add(T item)
        {
            Node<T> LastNode = new Node<T>(item, null);
            if (this.tHead == null)
            {
                this.tHead = LastNode;
            }
            else
            {
                Node<T> node = this.tHead;

                while (node.Next != null)
                {
                    node = node.Next;
                }
                node.Next = LastNode;
            }

        }

        public bool IsEmpty()
        {
            return this.tHead == null;
        }

        public T GetElement(int i)
        {
            if (i < 1 || i > this.GetLength())
            {
                Console.WriteLine("The location is not right!");
                return default(T);
            }
            else
            {
                if (i == 1)
                {
                    return this.tHead.Data;
                }
                else
                {
                    Node<T> node = this.tHead;
                    int j = 1;
                    while (j < i)
                    {
                        node = node.Next;
                        j++;
                    }
                    return node.Data;
                }
            }
        }

        public void Delete(int i)
        {
            if (i < 1 || i > this.GetLength())
            {
                Console.WriteLine("The location is not right!");
            }
            else
            {
                if (i == 1)
                {
                    Node<T> node = this.tHead;
                    this.tHead = node.Next;
                }
                else
                {
                    Node<T> node = this.tHead;
                    int j = 1;
                    while (j < i - 1)
                    {
                        node = node.Next;
                        j++;
                    }
                    node.Next = node.Next.Next;
                }
            }
        }

        public void Clear()
        {
            this.tHead = null;
        }

        public int LocateElement(T item)
        {
            if (this.tHead == null)
            {
                Console.WriteLine("There are no elements in this linked list!");
                return -1;
            }
            Node<T> node = this.tHead;
            int i = 0;
            while (node != null)
            {
                i++;
                if (node.Data.Equals(item))
                {
                    return i;
                }
                node = node.Next;
            }
            Console.WriteLine("No found!");
            return -1;
        }

        public void Reverse()
        {
            if (this.tHead == null)
            {
                Console.WriteLine("There are no elements in this linked list!");
            }
            else
            {
                Node<T> node = this.tHead;
                if (node.Next == null)
                {
                }
                else
                {
                    Node<T> node1 = node.Next;
                    Node<T> node2;
                    while (node1 != null)
                    {
                        node2 = node.Next.Next;
                        node.Next = node2;
                        node1.Next = this.tHead;
                        this.tHead = node1;
                        node1 = node2;
                    }
                }
            }
        }

        #endregion
    }
}
